package com.lenovo.nova.widget.ablistview;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Rect;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewTreeObserver;
import android.widget.ListAdapter;
import com.lenovo.nova.util.Applications;
import com.lenovo.nova.util.debug.MyOldLog;
import com.lenovo.nova.util.debug.mylog;
import com.lenovo.nova.util.debug.slog;
import com.lenovo.nova.widget.windowmanager.WindowManagerArrow;

@SuppressLint("NewApi")
public class HorizontalArrowBuilderHelper implements OnClickListener {


    private static final String TAG = "HorizontalArrowBuilderHelper";
    private static int ARROW_OFFSET_FOR_GABLE = 0;
    private static int ARROW_OFFSET_FOR_NEW_GUI = 25;

    private boolean initialized = false;

    private int mTopArrowOffSet;
    private int mBottomArrowOffSet;

    private ArrowHorizontalGridView mInstance;
    private String simpleName = null;
    private WindowManagerArrow arrow;
    private int mSmoothIndex;
    private CheckNeedWorkAround mCheckNeedWorkaround = new CheckNeedWorkAround();
    private OnHorizontalArrowClickListener listener;
    private int mScrollState;

    private boolean isUseDefaultArrow = true;

    public void setOnHorizontalArrowClickListener(OnHorizontalArrowClickListener l){
        listener = l;
    }

    public void setHostView(ArrowHorizontalGridView list) {
        mInstance = list;
        simpleName = list.getClass().getSimpleName();
        setTopArrowOffSet(ARROW_OFFSET_FOR_NEW_GUI);
        setBottomArrowOffSet(-ARROW_OFFSET_FOR_NEW_GUI);
    }

    public void nextSmoothScroll(boolean right) {

        View firstVisibleView = mInstance.getChildAt(0);

        float xOffSet = firstVisibleView.getX();

        int childViewWidth = firstVisibleView.getWidth();
        int horizontalSpacing = mInstance.getHorizontalSpacing();
        int nusColumn = mInstance.getNumColumn();
        mylog.i(TAG, " XOffSet " + xOffSet );

        //竖直方向距离de个数
        int scrollX = nusColumn * childViewWidth +
                //not use deltaDistance -1
                nusColumn * horizontalSpacing  -
                10
                ;

        mylog.i(TAG, " childViewWidth " + childViewWidth +
                        " horizontalSpacing " + horizontalSpacing +
                        " scrollX " + scrollX
        );

        int direction = right ? 1 : -1;
        if (direction > 0) {
            //-32 for work around the problem: when smooth finish , the getX() value of first item view is 0
            //the right will show some next item
            mInstance.smoothScrollBy((int) (scrollX + xOffSet) /*- 32*/, 1000);
        } else if (direction < 0) {
            mInstance.smoothScrollBy(-(scrollX - (int) xOffSet) /*+ 32*/ , 1000);
        }

    }

    public void onGlobalLayout() {
        refreshArrow();
    }

    public void onAttachedToWindow() {
        getViewTreeObserver().addOnGlobalLayoutListener(mInstance);
        if(isUseDefaultArrow){
            arrow = new WindowManagerArrow(getContext(),true);
            arrow.setOnClickListener(this);
            arrow.setBottomVisible(false);
            arrow.setTopVisible(false);
            arrow.setLeftVisible(false);
            arrow.setRightVisible(false);
        }

        if (getAdapter() != null && getAdapter().getCount() <= 1) {
            onSetTwoArrowVisible(false);
        }
    }

    @SuppressLint("MissingSuperCall")
    public void onDetachedFromWindow() {
        getViewTreeObserver().removeOnGlobalLayoutListener(mInstance);
        if(arrow != null){
            arrow.close();
            arrow.release();
            arrow = null;
        }
        initialized = false;
    }

    public void onLayout(boolean changed, int l, int t, int r, int b) {


    }

    public void onScroll(TwoWayAbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        mSmoothIndex = firstVisibleItem;
//        refreshArrow();
    }

    public void onScrollChanged(int l, int t, int oldl, int oldt) {
        // System.out.println(simpleName + " onScrollChanged");
        // 正常情况下，ListView滑动的时候会调用 onScroll ,onScrollChanged
        // 但是如果是在Popwindown中，ListView可能不会调用 onScroll
        slog.p(TAG, simpleName + "  onScrollChanged l " + l + "  t " + t + "  oldl " + oldl + "  oldt " + oldt);

//        refreshArrow();
    }

    public void onScrollStateChanged(TwoWayAbsListView view, int scrollState) {
        mScrollState = scrollState;
        if(scrollState == TwoWayAbsListView.OnScrollListener.SCROLL_STATE_IDLE){
            refreshArrow();

            View firstView = getChildAt(0);
            int firstViewX = (int) firstView.getX();
            mylog.d(TAG,"firstView tag " + firstView.getTag() +
                    " firstViewX " + firstViewX +
                    " mSmoothIndex " +mSmoothIndex +
                    "  " +scrollState);


            final int OFF_SET_FOR_SCROLL = 12;

            if(firstViewX < 0){
                int distance = - firstViewX;
                if(distance > firstView.getWidth() / 2){
                    if(getLastVisiblePosition() >= (mInstance.getCount() - 1)){
                        //at the last position
                        if(mCheckNeedWorkaround.isNeedStop(mSmoothIndex)){
                            mylog.w(TAG,"need work around error ");
                            return;
                        }
                    }

                    int offset = firstView.getWidth() - distance + mInstance.getHorizontalSpacing() - OFF_SET_FOR_SCROLL   ;
                    mylog.d(TAG,"right offset " + offset);
                    mInstance.smoothScrollBy(offset,1000);
                }else{
                    int offset =  -(distance + OFF_SET_FOR_SCROLL);
                    mylog.d(TAG,"left offset " + offset);

                    mInstance.smoothScrollBy(offset,1000);
                }
            }
        }
    }

    /**
     * 一般用不到，这个方法是在ListView或者GridView中，的Adapter的数据无效的时候调用,如下使用例子<br>
     * adapter.registerDataSetObserver(new DataSetObserver() {
     *
     * @Override public void onChanged() { slog.p(TAG, TAG +
     * " registerDataSetObserver onChanged " + getChildCount() + "   "
     * + getCount()); }
     * @Override public void onInvalidated() { slog.p(TAG, TAG +
     * " registerDataSetObserver onInvalidated " + getChildCount() +
     * "   " + getCount()); setTwoArrowVisible1(false); } });
     */
    public void onInvalidated() {
        onSetTwoArrowVisible(false);
    }

    @Override
    public void onClick(View v) {
        switch ((Integer)v.getTag()) {
            case WindowManagerArrow.ARROW_ID_LEFT:
                nextSmoothScroll(false);
                if(listener != null){
                    listener.onArrowClick(false);
                }
                break;
            case WindowManagerArrow.ARROW_ID_RIGHT:
                nextSmoothScroll(true);
                if(listener != null){
                    listener.onArrowClick(true);
                }
                break;
        }

    }

    public void setBottomArrowOffSet(int i) {
        mBottomArrowOffSet = i;
    }

    public void setTopArrowOffSet(int i) {
        mTopArrowOffSet = i;
    }

    public void setUseDefaultArrow(boolean useDefaultArrow){
        this.isUseDefaultArrow = useDefaultArrow;
    }


    private boolean isLastVisibleShow() {
        int lastVisiblePosition = getLastVisiblePosition();
        mylog.d(TAG,"lastVisiblePosition " + lastVisiblePosition + "  getCount " + getCount() );
        return lastVisiblePosition >= getCount() - 1;
    }

    @SuppressLint("NewApi")
    private boolean isFirstVisibleShow() {
        View firstChild = getChildAt(0);
        if (firstChild != null && (getFirstVisiblePosition() == 0)) {
            if (firstChild.getX() + 10 < 0) {
                return false;
            }
        }
        return getFirstVisiblePosition() == 0;
    }

    private int getDividerWidth() {
        return mInstance.getHorizontalSpacing();
    }

    private boolean isNeedShowArrow() {
        int mTotalChildWidth = 0;
        // add divider width
        int numberRow = mInstance.getNumRows();
        int contentColumn = getCount() % numberRow == 0 ? getCount() / numberRow : getCount() / numberRow + 1;
        mTotalChildWidth += getDividerWidth() * (contentColumn - 1);
        mTotalChildWidth += getPaddingLeft() + getPaddingRight();

        mylog.d(TAG,"isNeedShowArrow contentColumn " + contentColumn +
                " getCount " + getCount() +
                " numberRow " + numberRow +
                " mTotalChildWidth " + mTotalChildWidth
        );

        for (int i = 0; i < contentColumn ; i++) {
            if (getChildAt(0) != null) {
                int firstViewWidth = getChildAt(0).getWidth();
                mTotalChildWidth += firstViewWidth;
                if(mTotalChildWidth  > getWidth()){
                    mylog.d(TAG,"isNeedShowArrow mCurrentTotalChildWidth " + mTotalChildWidth +
                            " GridView getWidth " + getWidth() +
                            " firstViewWidth " + firstViewWidth +
                            " contentColumn " + contentColumn +
                            " getDividerWidth() " + getDividerWidth()
                    );
                    return true;
                }
            } else {
                mylog.w(TAG,"isNeedShowArrow getChildAt(0) is null");
            }
        }

        mylog.d(TAG,"isNeedShowArrow mTotalChildWidth " + mTotalChildWidth + " " + getWidth());
        return false;
    }

    /**
     * 该方法被调用一次就可以了，只是初始化上下箭头
     */
    private void initArrow() {
        if (!initialized) {
            initialized = true;
            boolean mCanFling = isNeedShowArrow();
            mylog.d(TAG, "initArrow  childTotalHeightAndPadding: " + " mCanFling is " + mCanFling);

            if (mCanFling && getWindowVisibility() == View.VISIBLE) {
                onSetShowRightArrow();
            } else {
                onSetTwoArrowVisible(false);
            }

        }
    }

    private int getPaddingRight() {

        return mInstance.getPaddingRight();
    }

    private int getPaddingLeft() {

        return mInstance.getPaddingLeft();
    }

    private void refreshArrow() {
        initArrow();

        if (getHeight() > 0 &&  getWindowVisibility() == View.VISIBLE) {
            // when the children height is less than the parent height,update
            // the arrow(set all arrows inVisible)
            Rect outRect = new Rect();
            getDrawingRect(outRect);
            boolean mCanFling = isNeedShowArrow();

            mylog.d(TAG, "refreshArrow  mCanFling " + mCanFling +
                            " isFirstVisibleShow() " + isFirstVisibleShow() +
                            " mSmoothIndex " + mSmoothIndex +
                            " isLastVisibleShow() " + isLastVisibleShow() +
                            " refreshArrow outRect " + outRect
            );

            if (mCanFling ) {
                if (isFirstVisibleShow() && mSmoothIndex == 0) {
                    onSetShowRightArrow();
                } else if (isLastVisibleShow()) {
                    onSetShowLeftArrow();
                } else {
                    onSetTwoArrowVisible(true);
                }
            } else {
                onSetTwoArrowVisible(false);
            }

            // 有时候ListView的高度需要跟随着变化，所以需要刷新箭头的额位置
            int[] location = new int[2];
            getLocationOnScreen(location);
            int[] locationInWind = new int[2];
            getLocationInWindow(locationInWind);

//            int topY = location[1] - arrow.getTopImageViewHeight();

            if(arrow != null){
                int topY = location[1] + (getHeight()  - arrow.getLeftImageHeight()) / 2;
                int leftX  = location[0] - arrow.getLeftImageWidth();
                int rightX = location[0] + getWidth() ;
                arrow.setLeftAndRightArrowY(topY);
                arrow.setLeftAndRightArrowX(leftX, rightX);
                mylog.d(TAG, "leftX " + leftX + "  rightX " + rightX + "  topY  " + topY);
            }

            mylog.d(TAG, "init arrow location is " + location[0] + "   " + location[1] + "\n " + locationInWind[0] + "  " + locationInWind[1]);
        }

    }

    protected void onSetShowLeftArrow() {
        if (arrow != null) {
            arrow.setLeftVisible(true);
            arrow.setRightVisible(false);
        }
        if (Applications.isInDebugMode) {
            MyOldLog.p("setShowTopArrow", MyOldLog.RANGE_LAST_METHOD);
        }
    }
    protected void onSetShowRightArrow() {
        if (arrow != null) {
            arrow.setLeftVisible(false);
            arrow.setRightVisible(true);
        }
    }
    protected void onSetTwoArrowVisible(boolean visible) {
        if (arrow != null) {
            arrow.setLeftVisible(visible);
            arrow.setRightVisible(visible);
        }
    }

    private View getChildAt(int i) {
        return mInstance.getChildAt(i);
    }

    private int getFirstVisiblePosition() {
        return mInstance.getFirstVisiblePosition();
    }

    private int getLastVisiblePosition() {
        return mInstance.getLastVisiblePosition();
    }

    private int getCount() {
        return mInstance.getCount();
    }

    private int getHeight() {
        return mInstance.getHeight();
    }

    private ListAdapter getAdapter() {
        return mInstance.getAdapter();
    }

    private void getLocationOnScreen(int[] location) {
        mInstance.getLocationOnScreen(location);

    }

    private void getLocationInWindow(int[] location) {
        mInstance.getLocationInWindow(location);

    }

    class CheckNeedWorkAround{
        int lastSmoothIndex = -1;
        int sameCont;
        public boolean isNeedStop(int mSmoothIndex) {
            if(lastSmoothIndex == mSmoothIndex){
                sameCont++;
            }

            if(sameCont != 0 && sameCont % 10 == 0){
                sameCont = -1;
                return true;
            }

            lastSmoothIndex = mSmoothIndex;
            return false;
        }
    }

    private ViewTreeObserver getViewTreeObserver() {
        return mInstance.getViewTreeObserver();
    }

    private int getWindowVisibility() {
        return mInstance.getWindowVisibility();
    }

    private void getDrawingRect(Rect outRect) {
        mInstance.getDrawingRect(outRect);
    }

    private int getWidth() {
        return mInstance.getWidth();
    }

    private Context getContext() {
        return mInstance.getContext();
    }

    public WindowManagerArrow getArrowManager() {
        return arrow;
    }

    public interface OnHorizontalArrowClickListener{
        void onArrowClick(boolean isRightClick);
    }
}
